package lancs.mobilemedia.monitor;

import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.reflect.SourceLocation;

import traceextractor.tracemodel.ExtractorControlGui;
import traceextractor.tracemodel.TraceFactory;


/**
 * Capture system execution events and forward to tracer threads.
 */
public aspect Monitor {
//  MEMBERS
	private TraceFactory factory;
    private ExtractorControlGui controlGui;
    private Map<Thread,TracerThread> tracersMap;
    {
    	factory = new TraceFactoryImpl();
    	tracersMap = new HashMap<Thread,TracerThread>();
    	controlGui = factory.createControlGui();
    	controlGui.getOutputDir();
    }
    
// POINTCUTS
    pointcut alocacaoDinamica(Object objeto) :
        initialization(*.new (..))
        && target(objeto)
        && !within(traceextractor..*);
    
    pointcut execucaoDeMetodo() :
    	execution(* *(..))
    	&& !within(traceextractor..*);
    
    pointcut operacao(Object objeto) :
    	target(objeto) 
    	&& !execution(* *(..))
    	&& !within(traceextractor..*);
    
    pointcut declaracao():
    	cflow(call(*.new(..)))
    	&& !within(traceextractor..*);
    
// ADVICES
//    before() : 
//    	execucaoDeMetodo() {
//    	System.out.println(thisJoinPoint.getSourceLocation().getFileName() + thisJoinPoint.getSourceLocation().getLine());
//   		tracer().registerEvent(thisJoinPoint, EventType.METHOD_ENTRY);
//   		
//    }
//    
//    after() : 
//    	execucaoDeMetodo() {
//    	
//   		tracer().registerEvent(thisJoinPoint, EventType.METHOD_EXIT);
//    }
//    
    // Registrar Criação de Objetos
//    before(Object objeto) : 
//    	alocacaoDinamica(objeto) {
//    	tracer().registerEvent(thisJoinPoint, EventType.CONSTRUCTOR_ENTRY);
//    	trace(thisJoinPoint.getSourceLocation(), objeto, "alocacao");
//    }
//    
//    after(Object objeto) :
//    	alocacaoDinamica(objeto) {
//    	
//    	tracer().registerEvent(thisJoinPoint, EventType.CONSTRUCTOR_EXIT);
//    }
//    
    before (Object objeto) : operacao(objeto){
//    	trace(thisJoinPoint.getSourceLocation(), objeto, "operacao");
    }
    
    before (): declaracao(){
    	System.out.println(thisJoinPoint);
    	trace(thisJoinPoint.getSourceLocation(), null, "declaracao");
    }
// METHODS
    public TracerThread tracer() {
    	Thread current = Thread.currentThread();
    	TracerThread tracer = null;
//    	synchronized(this) {
    		tracer = tracersMap.get(current);
    		if (null == tracer) {
    			tracer = new TracerThread(current, controlGui.getOutputDir(), factory);
    			tracersMap.put(current, tracer);
    			tracer.start();
    		}
//    	}
    	return tracer;
    }
    public void trace(SourceLocation src, Object obj, String type){
    	System.out.print(type+ ":::: " + src.getFileName()+" - " + src.getLine());
    	if(obj != null){
    		
    		System.out.println(" === " + obj.getClass().getName());
    	}else{
    		System.out.println();
    	}
    }
}
